import Rect from "../base/Rect"
import Food, { FoodType } from "./Food"
import SnakeNode from "../snake/SnakeNode"
import Config from "../config/Config"
import Snake from "../snake/Snake"
import { IBase } from "../base/Base"
import World from "./World"
import { Util } from "../util/Util"
import SnakeHead from "../snake/SnakeHead"

const cfg = Config.chunk
const util = Util

/** 区块构造参数 */
export interface IChunk extends IBase {
    /** 所在世界 */
    world: World
}

/** 区块 */
export default class Chunk extends Rect {

    /** 所在世界 */
    private _world: World
    /** 食物映射 */
    private _foodMap = new Map<FoodType, Set<Food>>()
    /** 蛇节点映射 */
    private _snakeNodeMap = new Map<Snake, Set<SnakeNode>>()
    /** 蛇头部节点集合 */
    private _snakeHeadSet = new Set<SnakeHead>()

    /** 实例化区块 */
    constructor(obj: IChunk) {
        super(obj);
        this._world = obj.world
        //创建食物集合
        this._foodMap.set(FoodType.normal, new Set())
        this._foodMap.set(FoodType.snake, new Set())
    }

    /** 添加食物 */
    addFood(food: Food) {
        this._foodMap.get(food.type).add(food)
        if (food.type == FoodType.normal) {
            if (this.normalFoodCount == cfg.foodMax) {
                //普通食物数量超出阈值从可生成食物区块中删除
                this._world.removeSpawnFoodChunk(this)
            }
        }
    }

    /** 移除食物 */
    removeFood(food: Food) {
        this._foodMap.get(food.type).delete(food)
        if (food.type == FoodType.normal) {
            if (this.normalFoodCount == cfg.foodMax - 1) {
                //普通食物数量回到阈值添加到可生成食物区块中
                this._world.addSpawnFoodChunk(this)
            }
        }
    }

    /** 添加蛇节点 */
    addSnakeNode(node: SnakeNode) {
        let nodes = this._snakeNodeMap.get(node.owner)
        if (!nodes) {
            nodes = new Set<SnakeNode>()
            this._snakeNodeMap.set(node.owner, nodes)
        }
        nodes.add(node)
    }

    /** 移除蛇节点 */
    removeSnakeNode(node: SnakeNode) {
        let nodes = this._snakeNodeMap.get(node.owner)
        if (nodes) {
            nodes.delete(node)
            //该蛇在此区块的节点数为0 将蛇从map中移除
            if (nodes.size == 0) {
                this._snakeNodeMap.delete(node.owner)
            }
        }
    }

    /** 添加蛇头部节点 */
    addSnakeHead(head: SnakeHead) {
        this._snakeHeadSet.add(head)
    }

    /** 移除蛇头部节点 */
    removeSnakeHead(head: SnakeHead) {
        this._snakeHeadSet.delete(head)
    }


    // ================================================================

    /** 普通食物数量 */
    get normalFoodCount() { return this._foodMap.get(FoodType.normal).size }

    /** 蛇节点集合 */
    get snakeNodeMap() { return this._snakeNodeMap }

    /** 蛇节点数量 */
    get snakeNodeCount() { return this._snakeNodeMap.size }

    /** 区块内的蛇集合 */
    get snakes() { return Array.from(this._snakeNodeMap.keys()) }

    /** 区块内的蛇头部节点集合 */
    get snakeHeads() { return Array.from(this._snakeHeadSet) }

    /** 区块内的蛇节点集合 */
    get snakeNodes() {
        let nodes: SnakeNode[] = []
        this._snakeNodeMap.forEach(ns => nodes = util.arrConcatSet(nodes, ns))
        return nodes
    }

    /** 获取区块内的食物 */
    get foods() {
        let foods: Food[] = [];
        this._foodMap.forEach(fs => foods = foods.concat(Array.from(fs)))
        return foods
    }

    /** 获取包含指定蛇集合的蛇节点集合 */
    getSnakeNodesInclude(include: Snake[]) {
        let snakeNodes: SnakeNode[] = []
        include.forEach(snake => {
            let nodeSet = this._snakeNodeMap.get(snake)
            if (nodeSet) {
                snakeNodes = snakeNodes.concat(Array.from(nodeSet))
            }
        })
        return snakeNodes
    }

    /** 获取不包含指定蛇集合的蛇节点集合 */
    getSnakeNodesExclude(exclude: Snake[]) {
        let include = Array.from(this._snakeNodeMap.keys())
        exclude.forEach(snake => util.arrRemoveItem(include, snake))
        return this.getSnakeNodesInclude(include)
    }

    /** 获取包含指定蛇集合的蛇节点映射 */
    getSnakeNodeMapInclude(include: Snake[]) {
        let snakeNodeMap = new Map<Snake, Set<SnakeNode>>()
        include.forEach(snake => {
            let nodeSet = this._snakeNodeMap.get(snake)
            if (nodeSet) {
                snakeNodeMap.set(snake, nodeSet)
            }
        })
        return snakeNodeMap
    }

    /** 获取不包含指定蛇集合的蛇节点映射 */
    getSnakeNodeMapExclude(exclude: Snake[]) {
        let include = Array.from(this._snakeNodeMap.keys())
        exclude.forEach(snake => util.arrRemoveItem(include, snake))
        return this.getSnakeNodeMapInclude(include)
    }

}